package com.fzu.geometa.metadata.controller;

import cn.hutool.http.HttpUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fzu.geometa.common.model.UserToken;
import com.fzu.geometa.common.model.dto.RestResponse;
import com.fzu.geometa.metadata.annotation.LoginRequired;
import com.fzu.geometa.metadata.annotation.UpdateSearch;
import com.fzu.geometa.metadata.eventdriven.event.MetadataDeleteEvent;
import com.fzu.geometa.metadata.eventdriven.publisher.MetadataEventPublisher;
import com.fzu.geometa.metadata.model.dto.DataBatchDeleteRequest;
import com.fzu.geometa.metadata.model.dto.DataDownloadRequest;
import com.fzu.geometa.metadata.model.dto.DataImportRequest;
import com.fzu.geometa.metadata.model.po.Register;
import com.fzu.geometa.metadata.service.MetadataService;
import com.fzu.geometa.metadata.service.RegisterService;
import com.fzu.geometa.metadata.util.HostHolder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import static com.fzu.geometa.common.model.dto.RestResponse.success;
import static com.fzu.geometa.common.model.dto.RestResponse.validFail;

@RestController
public class DateOperateController {
    @Autowired
    private RegisterService registerService;
    @Autowired
    private MetadataService metadataService;
    @Autowired
    private MetadataEventPublisher eventPublisher;

    @Autowired
    private HostHolder hostHolder;

    @PostMapping(path = "/dataImport")
    @LoginRequired
    public RestResponse dataImport(DataImportRequest dataImportRequest) throws IOException {
        // id 不能为空
        if (dataImportRequest == null || StringUtils.isBlank(dataImportRequest.getCoverageId())) {
            return validFail();
        }
        Register register = new Register();
        BeanUtils.copyProperties(dataImportRequest,register);
        register.setCreateTime(new Date());
        register.setUserId(hostHolder.getUser().getId());
        boolean res = false;
        // url
        if (DataImportRequest.METHOD_URL.equals(dataImportRequest.getMethod())) {
            try {
                res = metadataService.registerMetadata(register,new URL(dataImportRequest.getUrl()));
            } catch (Exception e) {
                e.printStackTrace();
                // 发生异常时，用 hutool 再试一次
                try {
                    String xml = HttpUtil.get(dataImportRequest.getUrl());
                    res = metadataService.registerMetadata(register,xml);
                } catch (Exception ex) {
                    e.printStackTrace();
                    return validFail();
                }
            }
        } else if (DataImportRequest.METHOD_FILE.equals(dataImportRequest.getMethod())) {
            // file
            MultipartFile file = dataImportRequest.getFile();
            res = metadataService.registerMetadata(register,file.getInputStream()) ;

        } else if (DataImportRequest.METHOD_Text.equals(dataImportRequest.getMethod())) {
            // text
            res =metadataService.registerMetadata(register,dataImportRequest.getText());
        }

        if (res) {
            eventPublisher.publishAddEvent(register.getCid());
            return success();
        } else {
            return validFail("不支持的类型");
        }
    }


    @GetMapping("/download")
    public ResponseEntity<Resource> download(DataDownloadRequest request) throws IOException {
        if (request == null) {
            throw new RuntimeException("请求为空");
        }
        // 从数据库中查询多个XML数据
        Map<String,String> dataMap = new HashMap<>();
        for (Long id : request.getIds()) {
            String coverageId = registerService.getCoverageIdByCid(id);
            dataMap.put(coverageId, metadataService.getMetadata(id));
        }

        // 创建一个临时文件夹来保存打包后的文件
        File zipFile = File.createTempFile("download", ".zip");
        zipFile.deleteOnExit();

        // 使用 ZipOutputStream 将文件打包成 Zip 文件
        FileOutputStream fos = new FileOutputStream(zipFile);
        ZipOutputStream zos = new ZipOutputStream(fos);

        // 循环遍历每个 XML 数据，并将其写入临时文件中
        dataMap.forEach((k,v)->{
            try {
                File xmlFile = File.createTempFile("tmp_" + k, ".xml"); // 文件名 prefix + 随机字符串 + suffix
                xmlFile.deleteOnExit();

                FileWriter writer = new FileWriter(xmlFile);
                writer.write(v);
                writer.close();

                // 文件重命名
                File newNameFile = new File(xmlFile.getParent(), k + ".xml");
                newNameFile.deleteOnExit();
                if (newNameFile.exists()) {  //  确保新的文件名不存在
                    newNameFile.delete();
                }

                if (!xmlFile.renameTo(newNameFile)) {
                    throw new RuntimeException(k + "下载异常");
                }

                xmlFile = newNameFile;

                // 将临时文件添加到 Zip 文件中
                ZipEntry zipEntry = new ZipEntry(xmlFile.getName());
                zos.putNextEntry(zipEntry);

                FileInputStream fis = new FileInputStream(xmlFile);
                byte[] buffer = new byte[1024];
                int len;
                while ((len = fis.read(buffer)) > 0) {
                    zos.write(buffer, 0, len);
                }
                fis.close();
                zos.closeEntry();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });

        zos.close();
        fos.close();

        // 将 Zip 文件包装为 Resource 对象
        FileSystemResource resource = new FileSystemResource(zipFile);

        // 设置响应头，告诉浏览器下载一个 Zip 文件
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=xml-files.zip");

        // 返回一个 ResponseEntity 对象，其中包含了 Zip 文件的内容
        return ResponseEntity.ok()
                .headers(headers)
                .contentLength(zipFile.length())
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(resource);
    }


    @PostMapping(path = "/batchDelete")
    public RestResponse batchDelete(DataBatchDeleteRequest request) {
        if (request == null) {
            return validFail();
        }

        if (metadataService.removeBatch(request.getIds())) {
            MetadataDeleteEvent metadataDeleteEvent = new MetadataDeleteEvent(this);
            for (Long cid : request.getIds()) {
                metadataDeleteEvent.addId(cid);
            }
            eventPublisher.publish(metadataDeleteEvent);
            return success();
        } else {
            return validFail();
        }
    }

    // 单个删除
    // （之前只删除了 register 表，要删除所有数据）
    @PostMapping(path = "/deleteMetadataById")
    public RestResponse deleteById(Long cid){
        if (cid == null) {
            return validFail();
        }
        if (metadataService.deleteMetaData(cid)) {
            eventPublisher.publishDeleteEvent(cid);
            return success();
        } else {
            return validFail();
        }
    }
}
